///******************** NG.Respate(C)  **********************************
//* 产品名称: Respate 科技
//* 文件名称: daemon.c
//* 程序作者: 雷帕特公司(南宫子萍)
//* 程序版本: V1.1														   
//* 编制日期: 2019/1/29
//* 功能描述: 守护进程
//* QQ:	2085827949
//**********************************************************************/
#ifndef __LAP_TFTP_H__
#define __LAP_TFTP_H__

#include <stdio.h>
#include "string.h"


// TFTP共定义了五种类型的包格式，格式的区分由包数据前两个字节的Opcode字段区分
typedef enum
{
	TFTP_RRQ   = 1,		// 读文件请求包：Read request，简写为RRQ，对应Opcode字段值为1
	TFTP_WRQ   = 2,		// 写文件请求包：Write requst，简写为WRQ，对应Opcode字段值为2
	TFTP_DATA  = 3,		// 文件数据包：Data，简写为DATA，对应Opcode字段值为3
	TFTP_ACK   = 4,		// 回应包：Acknowledgement，简写为ACK，对应Opcode字段值为4
	TFTP_ERROR = 5		// 错误信息包：Error，简写为ERROR，对应Opcode字段值为5
}TFTP_opCode;

// Mode:类型主要 可以是 "netascii", "octet", or "mail" (这几个单词的字母不区分大小写)
#define TFTP_MODE_NETAS "netascii"  // 文本格式模式
#define TFTP_MODE_OCTET "octet"     // 二进制模式
#define TFTP_MODE_MAIL  "mail"      // 不再支持

//    0         Not defined, see error message (if any).
//    1         File not found.
//    2         Access violation.
//    3         Disk full or allocation exceeded.
//    4         Illegal TFTP operation.
//    5         Unknown transfer ID.
//    6         File already exists.
//    7         No such user.

// TFTP共定义了五种类型的包格式，格式的区分由包数据前两个字节的Opcode字段区分
typedef enum
{
	TFTP_ERR_NOT_DEF  		= 0,		// 未定义，请参见错误消息（如果有）。
	TFTP_ERR_NO_FILE  		= 1,		// 找不到文件。
	TFTP_ERR_ACESE_VIOL		= 2,		// 访问冲突。
	TFTP_ERR_DISK_FULL		= 3,		// 磁盘已满或分配超出。
	TFTP_ERR_OP_ILLEGAL 	= 4,		// TFTP操作非法。
	TFTP_ERR_UNKNOW_ID 		= 5,		// 未知的传输ID。
	TFTP_ERR_FILE_EXISTS 	= 6,		// 文件已存在。
	TFTP_ERR_NO_USER 		= 7			// 没有这样的用户。
}tftp_errCode;


/* 1.TFTP 请求包(R/W)
 2 bytes     string    1 byte     string   1 byte
------------------------------------------------
| Opcode |  Filename  |   0  |    Mode    |   0  |
-----------------------------------------------
Opcode:   操作码(1:read 2:write)
Filename: netascii的文件字节序号，0表示终止
Mode:类型主要 可以是 "netascii", "octet", or "mail" (这几个单词的字母不区分大小写)
*/

typedef struct _tftp_pRrw
{
	short opcode;
	char* name;
	char* mode;
}tftp_pRrw;


/* 3.TFTP 数据包
 2 bytes     2 bytes      n bytes
----------------------------------
| Opcode |   Block    |   Data   |
----------------------------------

Block: 	从1开始，每一个新包自加。\
 		此限制，允许程序使用一个单一的数字来区分的新数据包之间的重复。\
 		每一个块的定长为512 （2^9）,如果出现某一块长度部位512，那就表示数据传输完成，终止传输。\
		  除了ACK和用于中断的包外，其它的包均得到确认。发出新的数据包等于确认上次的包。\
		WRQ和DATA包由ACK或ERROR数据包确认，而RRQ数据包由DATA或ERROR数据包确认。\
*/
typedef struct _tftp_pData
{
	short opcode;
	short block;
	char* data;
}tftp_pData; 



/* 4.TFTP 应答包(ACK)
2 bytes     2 bytes
---------------------
| Opcode |   Block   |
---------------------
*/
typedef struct _tftp_pAck
{
	short opcode;
	short block;
}tftp_pAck; 


/* 5.TFTP 错误包(ERR)
 2 bytes     2 bytes      string    1 byte
-----------------------------------------
| Opcode |  ErrorCode |   ErrMsg   |   0  |
-----------------------------------------
*/
typedef struct _tftp_pErr
{
	short opcode;
	short errcode;
	char* errmsg;
}tftp_pErr; 

// 
typedef union 
{
    tftp_pRrw   prw;    // 读写包
    tftp_pData  pdata;  // 数据包
    tftp_pAck   pack;   // 应答包
    tftp_pErr   perr;   // 错误包
}tftpPackage; 


typedef struct 
{
	int port;		// 服务器端口
	char ip[16];	// 服务器IP
	int block;		// 块大小
	char mode[10];		// 请求模式
    int retimes;    // 错误重传次数
    int timeout;    // 超时时间(us)
    char download[128]; // 下载路径
}tftpConfig;

// tftp 配置
extern tftpConfig tConfig;

int tftp_Pack2Stream(const tftpPackage* pack,char* buff,int num);
int tftp_Stream2Pack(tftpPackage* pack,const char* buff,int num);
void tftp_packInfo(FILE* fd,tftpPackage* pack,int len);
void test_printf(char* buff,int len);
int tftp_config(tftpConfig* config);
int tftp_printfConfig(tftpConfig* config);

#endif






																						 
